package com.XSQS.storage.index;

import java.io.IOException;
import java.io.RandomAccessFile;
import java.util.List;

import org.apache.log4j.Logger;

import com.XSQS.storage.helper.FileName;
import com.XSQS.storage.manager.FileManager;
import com.XSQS.util.Utility;

public class InvertedWriter {
	private Logger logger = Utility.getLogger(InvertedWriter.class);

	private static InvertedWriter instance;

	private FileManager fm;

	private RandomAccessFile entriesFile;
	private RandomAccessFile wordItemsFile;
	private RandomAccessFile metaWordItemsFile;

	private InvertedWriter() {
		fm = FileManager.getInstance();
	}

	public void open() {
		entriesFile = fm.openFile(FileName.getIndexEntriesFile());
		if (entriesFile == null) {
			entriesFile = fm.creatFile(FileName.getIndexEntriesFile());
		}
		wordItemsFile = fm.openFile(FileName.getWordItemsFile());
		if (wordItemsFile == null) {
			wordItemsFile = fm.creatFile(FileName.getWordItemsFile());
		}
		metaWordItemsFile = fm.openFile(FileName.getMetaWordItemsFile());
		if (metaWordItemsFile == null) {
			metaWordItemsFile = fm.creatFile(FileName.getMetaWordItemsFile());
		}
	}

	public void close() {
		fm.closeFile(FileName.getIndexEntriesFile());
		fm.closeFile(FileName.getWordItemsFile());
		fm.closeFile(FileName.getMetaWordItemsFile());
	}

	public synchronized static InvertedWriter getInstance() {
		if (instance == null) {
			instance = new InvertedWriter();
		}
		return instance;
	}

	public void writeIndexEntry(int index, IndexEntry entry) {
		try {
			entriesFile.seek(InvertedUtil.getEntriesFilePointer(index));
			entriesFile.write(entry.toByteArray());
		} catch (IOException e) {
			logger.error(e.getMessage());
		}
	}

	public void writeIndexEntry(IndexEntry entry) {
		try {
			entriesFile.seek(entriesFile.length());
			entriesFile.write(entry.toByteArray());
		} catch (IOException e) {
			logger.error(e.getMessage());
		}

	}

	public void writeIndexEntries(IndexEntry[] entries) {
		try {
			int size = entries.length * IndexEntry.LENGTH;
			byte[] buf = new byte[size];
			int pos = 0;
			for (IndexEntry entry : entries) {
				System.arraycopy(entry.toByteArray(), 0, buf, pos,
						IndexEntry.LENGTH);
				pos += IndexEntry.LENGTH;
			}
			entriesFile.seek(entriesFile.length());
			entriesFile.write(buf);
		} catch (IOException e) {
			logger.error(e.getMessage());
		}
	}

	public void writeIndexEntries(List<IndexEntry> entries) {
		try {
			int size = entries.size() * IndexEntry.LENGTH;
			byte[] buf = new byte[size];
			int pos = 0;
			for (IndexEntry entry : entries) {
				System.arraycopy(entry.toByteArray(), 0, buf, pos,
						IndexEntry.LENGTH);
				pos += IndexEntry.LENGTH;
			}
			entriesFile.seek(entriesFile.length());
			entriesFile.write(buf);
		} catch (IOException e) {
			logger.error(e.getMessage());
		}
	}

	public void writeWordItem(InvertedWordItem wordItem) {
		try {
			wordItemsFile.seek(wordItemsFile.length());
			
			/*Firstly, write the key length of the specified InvertedWordItem*/
			int keyLength=wordItem.getKey().length();
			if(keyLength>255){
				logger.error("The length of key is not allowd to be larger then 255.");
			}
			wordItemsFile.write(keyLength);
			
			wordItemsFile.write(wordItem.toByteArray());
			
			if (logger.isDebugEnabled()) {
				logger.debug(wordItem.getKey() + " "
							+ wordItem.getFirstEntry() + " "
							+ wordItem.getLastEntry());
			}
		} catch (IOException e) {
			logger.error(e.getMessage());
		}
	}

	public void writeWordItems(InvertedWordItem[] wordItems) {
		writeWordItems(wordItems,0,wordItems.length);
	}
	
	public void rewriteWordItems(InvertedWordItem[] wordItems){
		rewriteWordItems(wordItems,0,wordItems.length);
	}
	
	/**
	 * 
	 * @param wordItems 
	 * @param fromIndex the index of the first element (inclusive) to be written.
	 * @param toIndex the index of the last element (exclusive) to be written.
	 */
	public void writeWordItems(InvertedWordItem[] wordItems,int fromIndex,int toIndex) {
		for(int i=fromIndex;i<toIndex;++i){
			writeWordItem(wordItems[i]);
		}
	}
	
	/**
	 * 
	 * @param wordItems 
	 * @param fromIndex the index of the first element (inclusive) to be rewritten.
	 * @param toIndex the index of the last element (exclusive) to be rewritten.
	 */
	public void rewriteWordItems(InvertedWordItem[] wordItems,int fromIndex,int toIndex){
		try {
			wordItemsFile.setLength(0);
			writeWordItems(wordItems,fromIndex,toIndex);
		} catch (IOException e) {
			logger.error(e.getMessage());
		}
	}
}
